{-# LANGUAGE TemplateHaskell #-}

module Vote.Internal.Config where

import Control.Lens (makeLenses)
import Control.Monad.Logger (logErrorN, logInfoN, runStdoutLoggingT)
import Control.Monad.Trans.Resource (runResourceT)
import Data.Aeson.TH (Options (..), deriveJSON)
import Data.Data (Data)
import Data.Text (pack)
import Data.Yaml (decodeFileEither)
import Protolude
import System.Directory (getCurrentDirectory)
import System.FilePath ((</>))
import Vote.Internal.Aeson (toJSONOptions)
import Vote.Internal.Util (trimPrefixName_)

data Admin = Admin
  { _adminName :: !Text,
    _adminPass :: !Text
  }
  deriving (Eq, Show, Data, Generic)

deriveJSON (toJSONOptions {fieldLabelModifier = trimPrefixName_ ''Admin}) ''Admin

makeLenses ''Admin

newtype Conn = Conn
  { _connPostgreSQL :: Text
  }
  deriving (Show, Eq, Data, Generic)

deriveJSON (toJSONOptions {fieldLabelModifier = trimPrefixName_ ''Conn}) ''Conn

makeLenses ''Conn

data Dir = Dir
  { _dirStatic :: !Text,
    _dirLog :: !Text
  }
  deriving (Show, Eq, Data, Generic)

deriveJSON (toJSONOptions {fieldLabelModifier = trimPrefixName_ ''Dir}) ''Dir

makeLenses ''Dir

newtype Path = Path
  { _pathStatic :: Text
  }
  deriving (Show, Eq, Data, Generic)

deriveJSON (toJSONOptions {fieldLabelModifier = trimPrefixName_ ''Path}) ''Path

makeLenses ''Path

data Site = Site
  { _sitePort :: !Int,
    _sitePath :: !Path
  }
  deriving (Eq, Show, Data, Generic)

deriveJSON (toJSONOptions {fieldLabelModifier = trimPrefixName_ ''Site}) ''Site

makeLenses ''Site

data Config = Config
  { _configVersion :: !Text,
    _configEnv :: !Text,
    _configAdmin :: !Admin,
    _configConn :: !Conn,
    _configDir :: !Dir,
    _configSite :: Site
  }
  deriving (Eq, Show, Data, Generic)

deriveJSON (toJSONOptions {fieldLabelModifier = trimPrefixName_ ''Config}) ''Config

makeLenses ''Config

loadConfig :: IO (Maybe Config)
loadConfig = runStdoutLoggingT . runResourceT $ do
  let logPre = "[LOAD CONFIG]"
  curDir <- liftIO getCurrentDirectory
  let cfgPath = curDir </> "config.yml"
  parseResult <- liftIO $ decodeFileEither cfgPath
  case parseResult of
    Left e -> do
      logErrorN . pack $ logPre <> show e
      return Nothing
    Right v -> do
      logInfoN . pack $ logPre <> show v
      return $ Just v